﻿/*
____
 L|ypps Web controls for ASP.NET

Copyright (c) 2009 Alessandro Zifiglio, http://www.Typps.com
EMail: alessandro@Typps.com

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
namespace Typps.Tests
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    using Microsoft.VisualStudio.TestTools.UnitTesting;

    using Typps;

    /// <summary>
    /// Summary description for UnitTestSgmlDtdParser
    /// </summary>
    [TestClass]
    public class UnitTestSgmlDtdParser
    {
        #region Fields

        private TestContext testContextInstance;

        #endregion Fields

        #region Constructors

        public UnitTestSgmlDtdParser()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        #endregion Constructors

        #region Properties

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #endregion Properties

        #region Methods

        [TestMethod]
        public void Parsehtml_do_not_format_output()
        {
            HtmlDtdParser dtd = new HtmlDtdParser(DtdSchema.XhtmlTransitional);
            dtd.PrettyHtml = false;//no formatting?

            string html = @"<html><head></head><body><p><div>Hello</div></p></body></html>";//div not allowed in p?
            string output = "<html><head></head><body><p></p><div>Hello</div></body></html>";

            ParsedSourceContent result = dtd.ParseHtml(html);
            result = dtd.ParseHtml(html);
            Assert.AreEqual(result.Source, output);
        }

        [TestMethod]
        public void ParseHTML_Entity_IsPreserved()
        {
            HtmlDtdParser dtd = new HtmlDtdParser(DtdSchema.XhtmlTransitional);
            //note nested p, shouldn't be allowed. align attribute should be stripped, deprecated?
            string html = @"<html><body><p>&amp;</p></body></html>";
            /*&amp; is a named or entity character reference and &#38; is a numerical character reference. our parser uses the numerical character reference.
             this is essentially the same thing since &amp is simply an alias for &#38*/
            string output =
            @"<html>
              <body>
            <p>&#38;</p>
              </body>
            </html>";
            ParsedSourceContent result = dtd.ParseHtml(html);
            Assert.AreEqual(result.Source, output);
        }

        [TestMethod]
        public void Parsehtml_frameset_doctype_allows_iframe_element()
        {
            HtmlDtdParser dtd = new HtmlDtdParser(DtdSchema.XhtmlFrameset);

            string html = "<html><head></head><body><div><iframe></iframe></div></body></html>";
            ParsedSourceContent result = dtd.ParseHtml(html);
            Assert.AreEqual(result.FailureMessage, string.Empty);
        }

        [TestMethod]
        public void Parsehtml_ignore_pre_elements()
        {
            HtmlDtdParser dtd = new HtmlDtdParser(DtdSchema.XhtmlTransitional);

            //contains pre elements (we don't touch pre element contents, however we make some simple corrections)
            //eg: we still fix casing and unclosed br tag
            string html = "<html><head></head><body><div class=\"linecontent\">\r\n            <PRE><Span style=\"color:#0000FF\">private</span> <span style=\"color:#0000FF\">void</span> AddHighlighter(HighlighterBase highlighter)\r\n <br>       {\r\n            <span style=\"color:#0000FF\">this</span>.highlighters.Add(highlighter);\r\n        }</pre>\r\n        </div></body></html>";
            string output =
            @"<html>
              <head></head>
              <body>
            <div class=""linecontent"">
            <pre><span style=""color:#0000FF"">private</span> <span style=""color:#0000FF"">void</span> AddHighlighter(HighlighterBase highlighter)
             <br />       {
            <span style=""color:#0000FF"">this</span>.highlighters.Add(highlighter);
            }</pre>
            </div>
              </body>
            </html>";
            ParsedSourceContent result = dtd.ParseHtml(html);
            result = dtd.ParseHtml(html);
            Assert.AreEqual(result.Source, output);
        }

        [TestMethod]
        public void ParseHTML_LineFeedInsideInlineStyle_LineFeedHTMLEntityEquivalent()
        {
            HtmlDtdParser dtd = new HtmlDtdParser(DtdSchema.XhtmlTransitional);
            //note nested p, shouldn't be allowed. align attribute should be stripped, deprecated?
            string html = @"<html><body><p style=""margin:
            0cm;
            "">hello</p></body></html>";
            /*note how \r\n in the style attribute got converted to html entity equivalents. adding linefeeds inside an attributes value is just wrong so
             the best thing to do is avoid doing that*/
            string output =
            @"<html>
              <body>
            <p style=""margin:&#xD;&#xA;            0cm;&#xD;&#xA;            "">hello</p>
              </body>
            </html>";
            ParsedSourceContent result = dtd.ParseHtml(html);
            Assert.AreEqual(result.Source, output);
        }

        [TestMethod]
        public void Parsehtml_missing_closing_div()
        {
            HtmlDtdParser dtd = new HtmlDtdParser(DtdSchema.XhtmlTransitional);
            string html = @"<html><head></head><body><div>Hello</body></html>";//missing closing div
            string output =
            @"<html>
              <head></head>
              <body>
            <div>Hello</div>
              </body>
            </html>";
            ParsedSourceContent result = dtd.ParseHtml(html);
            result = dtd.ParseHtml(html);
            Assert.AreEqual(result.Source, output);
        }

        [TestMethod]
        public void Parsehtml_strict_doctype_does_not_allows_deprecated_html_attributes()
        {
            HtmlDtdParser dtd = new HtmlDtdParser(DtdSchema.XhtmlStrict);
            //note nested p, shouldn't be allowed. align attribute should be stripped, deprecated?
            string html = "<html><head></head><body><p align=\"center\">a<p>b</p></p></body></head></html>";

            string output =
            @"<html>
              <head></head>
              <body>
            <p>a</p>
            <p>b</p>
              </body>
            </html>";
            ParsedSourceContent result = dtd.ParseHtml(html);
            Assert.AreEqual(result.Source, output);
            Assert.AreNotEqual(result.FailureMessage, string.Empty);
        }

        [TestMethod]
        public void Parsehtml_strict_doctype_does_not_allows_iframe_element()
        {
            HtmlDtdParser dtd = new HtmlDtdParser(DtdSchema.XhtmlStrict);

            string html = "<html><head></head><body><div><iframe></iframe></div></body></html>";
            string output = "### Error:Element 'iframe' is not allowed or reconized with the current doctype.    \nReferenced on line 1, position 40 of internal entity '#document'\r\n";
            ParsedSourceContent result = dtd.ParseHtml(html);
            Assert.AreEqual(result.FailureMessage, output);
        }

        [TestMethod]
        public void Parsehtml_transitional_doctype_allows_deprecated_html_attributes()
        {
            HtmlDtdParser dtd = new HtmlDtdParser(DtdSchema.XhtmlTransitional);
            //note nested p, shouldn't be allowed. align attribute should be stripped, deprecated?
            string html = "<html><head></head><body><p align=\"center\">a<p>b</p></p></body></head></html>";

            string output =
            @"<html>
              <head></head>
              <body>
            <p align=""center"">a</p>
            <p>b</p>
              </body>
            </html>";
            ParsedSourceContent result = dtd.ParseHtml(html);
            Assert.AreEqual(result.Source, output);
        }

		[TestMethod]
		public void Parsehtml_strict_doctype_nested_nested_element_causes_problems()
		{
			HtmlDtdParser dtd = new HtmlDtdParser(DtdSchema.XhtmlStrict );
			dtd.PrettyHtml = false;//no formatting?

			string html = @"<html><body><a></a><p></p></body></html>";
			string output = @"<html><body></body><a></a><p></p></html>";

			ParsedSourceContent result = dtd.ParseHtml(html);
			result = dtd.ParseHtml(html);
			/*This is not as good as it looks. the p element should actually be inside the body tags. But we have a fastforward only html parser!
			 we're going to have to write a new one that is clientside only and work better without a serverside dependency.*/
			Assert.AreEqual( result.Source, output);
		}
        #endregion Methods

        #region Other

        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //

        #endregion Other
    }
}